import { existsSync, mkdirpSync, readdir, readdirSync, readFile, readFileSync, writeFileSync } from 'fs-extra';
import path, { join, normalize, relative, resolve } from 'path';
import { Tools } from './Tools';
import * as os from "os"
import { exec } from "child_process";
import { accessSync, copyFile, copyFileSync, renameSync, statSync, writeFile } from 'fs';
import { promisify } from 'util';
import { AndroidBuilder } from './AndroidBuilder';
import { channel } from 'diagnostics_channel';
// import { S3Client, PutObjectCommand, PutObjectCommandInput } from '@aws-sdk/client-s3';
import { encryptFolder, writeInCpp } from './encrypt';
import { postUploadZip } from './funcs';
// let OSS = require("ali-oss")
const fs = require('fs');
const PACKAGE_MAIN = "res"
const PACKAGE_NAME = "project-update";
const exec_promisify = promisify(exec);
const bucketName = 'cbreak'; 

const isIOS = os.type() == 'Darwin';

class Helper {
    constructor() {
        this.readCacheConfig()
        // this._config.buildDir = path.join(Editor.Project.path, "build")
        // this._config.buildOutDir = path.join(Editor.Project.path, "build/assetsbundle")
        // if (!existsSync(this._config.buildOutDir)) {
        //     Tools.mkdirSync(this._config.buildOutDir);
        // }
        AndroidBuilder.buildDir = path.join(this.config.buildDir, "proj");
        AndroidBuilder.channelId = this.config.channelCfg;
    }

    private _config: HotupdateConfig = null!
    private _buildConfig: any = null!
    get config() {
        if (!this._config) {
            this.readCacheConfig();
        }
        return this._config;
    }
    set config(v) {
        this._config = v;
    }

    get buildConfig() {
        if (!this._buildConfig) {
            this.readBuildConfig();
        }
        return this._buildConfig;
    }

    private _bundles: { [key: string]: BundleCfg } | null = null;
    get bundles() {
        if (!this._bundles) {
            this._bundles = this.readBundlesCfg();
        }
        return this._bundles;
    }

    //游戏打包配置
    private _packageCfg: PackageCfg[] | null = null
    get PackageCfgs() {
        if (!this._packageCfg) {
            this._packageCfg = this.readPackageCfg();
        }
        console.log('########### PackageCfgs---> ',this._packageCfg)
        return this._packageCfg;
    }
    //游戏服务器配置
    private _serverCfgs: ServerCfg[] | null = null
    get ServerCfgs() {
        if (!this._serverCfgs) {
            this._serverCfgs = this.readServerCfg();
        }
        return this._serverCfgs;
    }
    //游戏渠道号配置
    private _channelCfgs: string[] | null = null
    get ChannelCfgs() {
        if (!this._channelCfgs) {
            this._channelCfgs = this.readChannelCfg();
        }
        return this._channelCfgs;
    }

    private get buildOutPath() {
        return path.join(this.config.buildOutDir, this.envName)
    }

    private get envName() {
        if (this.isRelease) {
            return "release"
        } else {
            return "test"
        }
    }

    public get isRelease() {
        return this.config.serverCfg.name == "正式服"
    }

    //获取缓存配置
    private get userCachePath() {
        return path.join(Editor.Project.path, "extensions/project-update/config/localCache.json");
    }

    //获取对应平台的buildconfig
    private get buildConfigPath() {
        return path.join(Editor.Project.path, `extensions/project-update/config/buildConfig_${this.config.platform}.json`)
    }

    public setProjectPath(path: string) {
        this.config.projectPath = path;
    }

    public setBuildPath(pt: string) {
        this.config.buildDir = pt;
        AndroidBuilder.buildDir = path.join(pt, "proj");
    }

    public setBuildOutPath(pt: string) {
        this.config.buildOutDir = pt;
    }

    /**@description 保存当前用户设置 */
    saveConfig() {
        let cacheString = JSON.stringify(this.config);
        writeFileSync(this.userCachePath, cacheString);
        // this.addLog(`写入缓存 :`, this.userCache);
    }

    saveBundleCfg(){
        let cfg = []
        for(var key in this.bundles){
            let info = this.bundles[key]
            let vo = {
                name : info.name,
                bundle :info.bundle,
                relative:info.relative,
                respaths:info.respaths,
                version:info.version
            }
            cfg.push(vo)
        }
        let filePath = path.join(Editor.Project.path, "extensions/project-update/config/bundles.json");
        writeFileSync(filePath, JSON.stringify(cfg), { "encoding": "utf8" });
    }

    /**@description 保存打包配置 */
    savePackageCfg() {
        let filePath = path.join(Editor.Project.path, "extensions/project-update/config/packagecfg.json");
        // 找到与 config.name 匹配的元素索引
        let index = this.PackageCfgs.findIndex(pkg => pkg.name === this.config.packageCfg.name);
        // 如果找到相同的 name，则用 config 覆盖该元素
        if (index !== -1) {
            this.PackageCfgs[index] = this.config.packageCfg;
        }
        writeFileSync(filePath, JSON.stringify(this.PackageCfgs), { "encoding": "utf8" });
    }

    /**@description 读取本地缓存 */
    readCacheConfig() {
        if (existsSync(this.userCachePath)) {
            let data = readFileSync(this.userCachePath, "utf-8")
            this._config = JSON.parse(data);
        } else {
            this._config = new HotupdateConfig();
        }

        if (this._config.serverCfg) {
            let name = this._config.serverCfg.name;
            for (let i = 0; i < this.ServerCfgs.length; i++) {
                if (this.ServerCfgs[i].name == name) {
                    this._config.serverCfg = this.ServerCfgs[i]
                    break;
                }
            }
        }
        else {
            this._config.serverCfg = this.ServerCfgs[0];
        }
    }
    readBuildConfig() {
        let data = readFileSync(this.buildConfigPath, "utf-8")
        this._buildConfig = JSON.parse(data);
    }

    readServerCfg() {
        let filePath = path.join(Editor.Project.path, `extensions/project-update/config/servercfg.json`)
        let cfgs: ServerCfg[] = []
        if (existsSync(filePath)) {
            let data = readFileSync(filePath, "utf-8")
            cfgs = JSON.parse(data)
        }
        return cfgs
    }

    readChannelCfg() {
        let filePath = path.join(Editor.Project.path, `extensions/project-update/config/channels.json`)
        let cfgs: string[] = []
        if (existsSync(filePath)) {
            let data = readFileSync(filePath, "utf-8")
            cfgs = JSON.parse(data)
        }
        return cfgs
    }

    /**@description 读取本地bundle配置文件 */
    readBundlesCfg() {
        let filePath = path.join(Editor.Project.path, "extensions/project-update/config/bundles.json");
        let bundles: { [key: string]: BundleCfg } = {}
        if (existsSync(filePath)) {
            let data = readFileSync(filePath, "utf-8")
            let assets = JSON.parse(data);
            for (let i = 0; i < assets.length; i++) {
                var asset = assets[i]
                if (asset) {      
                    let cfg: BundleCfg = {
                        relative: asset.relative,
                        bundle: asset.bundle,
                        name: asset.name,
                        respaths: asset.respaths,
                        version: asset.version || '1.1.1',
                        // versions: versions,
                        // version: versions[0],
                        select: false,
                    }
                    
                    bundles[cfg.bundle] = cfg
                }
            }
        }
        return bundles;
    }

    //获取本地
    getLocalVersions(bundle: string, platform: string) {
        var assetPath = path.join(this.buildOutPath, bundle, platform)
        if (existsSync(assetPath))
            return readdirSync(assetPath);
        return [];
    }

    /**@description 读取本地打包配置文件 */
    readPackageCfg() {
        let filePath = path.join(Editor.Project.path, "extensions/project-update/config/packagecfg.json")
        let packageCfg: PackageCfg[] = []
        if (existsSync(filePath)) {
            let data = readFileSync(filePath, "utf-8")
            let assets = JSON.parse(data);
            for (let i = 0; i < assets.length; i++) {
                var asset = assets[i]
                if (asset) {

                    let cfg: PackageCfg = {
                        name: asset.name,
                        versionName: asset.versionName,
                        versionCode: asset.versionCode,
                        packageName: asset.packageName,
                        appId: asset.appId,
                        facebookId:asset.facebookId,
                        facebookToken:asset.facebookToken,
                        googleId:asset.googleId,
                        AdjustId:asset.AdjustId,
                        buglyId:asset.buglyId,
                    }
                    packageCfg.push(cfg)
                }
            }
        }
        return packageCfg;
    }

    /**
     * @description 添加日志
     * @param {*} message 
     * @param {*} obj 
     * @returns 
     */
    log(message: any, obj: any = null) {
        if (typeof obj == "function") {
            return;
        }
        if (obj) {
            console.log(message, obj);
        } else {
            console.log(message);
        }
    }

    setServerCfg(name: string) {
        let cfg = this.ServerCfgs.find((a) => a.name == name)
        if (cfg) {
            this.config.serverCfg = cfg;
            this._bundles = this.readBundlesCfg()
            Editor.Message.send(PACKAGE_NAME, "onRefresh");
        }
    }

    setChannelCfg(channel: string) {
        let cfg = this.ChannelCfgs.find((a) => a == channel)
        if (cfg) {
            this.config.channelCfg = cfg;
            AndroidBuilder.channelId = this.config.channelCfg;
        }
    }

    setPackageCfg(packageName: string) {
        this.config.packageCfg = this.PackageCfgs.find((a) => a.name == packageName) as PackageCfg;
        console.log("setPackageCfg ", this.config.packageCfg)
    }

    setplatform(platform: string) {
        this.config.platform = platform;
        // for (var bundle in this.bundles) {
        //     var versions = this.getLocalVersions(bundle, this.config.platform).sort().reverse()
        //     this.bundles[bundle].versions = versions;
        //     this.bundles[bundle].version = versions[0];
        // }
    }

    private async onChangeGameConfig() {
        let scenePath = path.join(Editor.Project.path, "assets/main.scene");
        let fileContent = readFileSync(scenePath, "utf8");
        if (this.config.serverCfg.name == "测试服") {
            fileContent = fileContent.replace(/\"_envType\": \d/g, `\"_envType\": 0`)
        } else {
            fileContent = fileContent.replace(/\"_envType\": \d/g, `\"_envType\": 1`)
        }
        // versionName
        fileContent = fileContent.replace(/\"_version\": \"[\d\.]*\"/g, `\"_version\": \"${this.config.versionName}\"`);
        // versionCode
        fileContent = fileContent.replace(/\"_versionCode\": \d+/g, `\"_versionCode\": ${this.config.versionCode}`);
        writeFileSync(scenePath, fileContent, { "encoding": "utf8" });

        await Editor.Message.request("asset-db", "refresh-asset", scenePath);
    }

    //插入热更新代码
    private onInsertHotupdate(dest: string) {
        let codePath = path.join(Editor.Project.path, "extensions/project-update/code/hotupdate.js");
        let code = readFileSync(codePath, "utf8");
        // console.log(code);
        let sourcePath = path.join(dest, "assets/main.js");
        sourcePath = normalize(sourcePath);
        let sourceCode = readFileSync(sourcePath, "utf8");
        let templateReplace = function templateReplace() {
            // console.log(arguments);
            return arguments[1] + code + arguments[3];
        }
        //添加子游戏测试环境版本号
        sourceCode = sourceCode.replace(/(\);)([\s\w\S]*)(const[ ]*importMapJson)/g, templateReplace);
        this.log(`向${sourcePath}中插入热更新代码`);
        writeFileSync(sourcePath, sourceCode, { "encoding": "utf8" });
    }

    //留给web用?
    onCreateAllManifest() {
        if (!this.bundles)
            return;
        let assetDir = path.join(this.config.buildDir, "assets")
        for (var key in this.bundles) {
            var cfg = this.bundles[key]
            let manifest = this.onCreateManifest(cfg.bundle)
            if (manifest) {
                writeFileSync(path.join(assetDir, cfg.relative, "project.manifest"), JSON.stringify(manifest));
            }
        }
        console.log("生成包内版本文件成功...")
    }

    //获取本地
    // getLocalVersions(bundle: string, platform: string) {
    //     var assetPath = path.join(this.buildOutPath, bundle, platform)
    //     if (existsSync(assetPath))
    //         return readdirSync(assetPath);
    //     return [];
    // }

    getCommitUrl(info: BundleCfg): string | undefined {
        if (!info.version) {
            return undefined;
        }
        // var plat = "android"
        // var url = this.config.serverCfg.res_address + "?a=resMan&optype=committodb&";
        // console.log(url)
        // var paramDic: { [key: string]: string } = {};
        // paramDic.pf = plat;
        // paramDic.mids = plat + "_none"
        // paramDic.bunldidfilter = info.bundle
        // paramDic.ver = info.version
        // paramDic.skinver = "1"

        // let keys = []
        // for (let k in paramDic) {
        //     keys.push(k)
        // }
        // keys.sort((a: string, b: string) => {
        //     return a.localeCompare(b)
        // })
        // let addKey = ""
        // for (let i = 0; i < keys.length; i++) {
        //     let v = keys[i]
        //     addKey = addKey + (v + "=" + paramDic[v] + "&")
        // }
        // addKey += "key=" + "03346b68aa44c87129438bd650f11a66";
        // console.log("addKey -------->", addKey)

        // var commitUrl = `params=pf,${plat}`
        // commitUrl += `|mids,${plat}_none`
        // commitUrl += `|bunldidfilter,${info.bundle}`
        // commitUrl += `|ver,${info.version}`
        // commitUrl += `|skinver,1`
        // commitUrl += `|sign,${require("crypto").createHash('md5').update(addKey).digest('hex')}`
        // url += commitUrl;
        // return url;
    }
    //更改版本号
    onChangeVersion(bundle: string, ver: string) {
        ver = ver.trim();
        if (this.bundles[bundle]) {
            this.bundles[bundle].version = ver;
            this.saveBundleCfg()
        }
    }

    //获取版本号
    onGetVersionFromServer(info: BundleCfg) {
        let url = this.getCommitUrl(info);
        if (!url) {
            return
        }
        // this.http_post("/backend/basic/refresh", (data: string) => {
        //     console.log("提交成功  " + data)
        // })
    }

    //提交版本号
    onCommitVersionToServer(info: BundleCfg) {
        let url = this.getCommitUrl(info);
        if (!url) {
            return
        }
        this.http_get(url, (data: string) => {
            console.log("提交成功  " + data)
        })
    }

    //生成提交配置
    public createCommitCfg(info: any) {
        let configFilePath = this.buildOutPath + "/config.json"

        if (!existsSync(configFilePath)) {
            // 如果 config.json 不存在，创建并写入内容
            writeFileSync(configFilePath, JSON.stringify(info, null, 4));
            console.log('[配置文件] 创建成功:', configFilePath);
        } else {
            console.log('[配置文件] 已存在:', configFilePath);
            writeFileSync(configFilePath, JSON.stringify(info));
        }
        console.log('[配置文件] 写入成功:', info);

        console.log("=======================生成远程配置文件成功========================")
    }
    async onBuildAssets() {
        console.log("=======================构建开始========================")
        const bEncrypt = helper.config.isEncrypt;
        console.log('onBuildAssets',bEncrypt);
        if (bEncrypt) {
            await writeInCpp(this.config.enginePath);
        }
        await this.onBuild();
        console.log("拷贝资源到工程目录")
        let tmpAssetPath = path.join(this.config.buildDir, "tmpAssets")
        Tools.delDir(tmpAssetPath, true);
        Tools.mkdirSync(tmpAssetPath);
        for (var key in this.bundles) {
            var cfg = this.bundles[key]
            if (cfg.select || cfg.bundle == PACKAGE_MAIN) {
                let ver = this.onCreateVersion();
                console.log(`自动生成 ${cfg.bundle} 版本号 ${ver}`);
                cfg.version = ver;
                await this.onCreateBundle(cfg.bundle, bEncrypt, path.join(tmpAssetPath, cfg.relative))
            }
        }
        //保存bundle版本
        this.saveBundleCfg()
        let assetPath = path.join(this.config.buildDir, "data")
        copyFileSync(path.join(assetPath, "application.js"), path.join(tmpAssetPath, "application.js"))
        copyFileSync(path.join(assetPath, "main.js"), path.join(tmpAssetPath, "main.js"))
        Tools.delDir(assetPath, true);
        renameSync(tmpAssetPath, assetPath );
        console.log("资源拷贝结束")
        console.log("=======================构建结束========================")
    }
    //资源构建
    async onBuildAssetBundles(encrypt=false) {
        console.log("=======================资源发布开始========================")
        console.log('onBuildAssetBundles',encrypt);
        if (encrypt) {
            await writeInCpp(this.config.enginePath);
        }
        if (this.config.autoCreate) {
            await this.onBuild();
        }
        await this.onCreateAssetBundles(encrypt);
        // await this.onDeployToSVN();
        await this.uploadAssetBundles();
        //保存bundle版本
        this.saveBundleCfg()
        console.log("=======================资源发布结束========================")
    }
    
    private async uploadAssetBundles() {
        // 先将根目录打包成zip
        const envName = this.envName;
        const path0 = this.buildOutPath;
        const path1 = this.config.buildOutDir;
        const zipPath = await Tools.zipDirc(path0, path1, envName);
        console.log(`压缩完成，准备上传: ${zipPath}`);
        const url = this.config.serverCfg.upload_url;
        // 明天来弄上传部分
        const res = await postUploadZip(url, {
            env: envName,
            filePath: zipPath,
            fileName: `${envName}.zip`
        });
        console.log('上传结果', res);
    }

    //创建bundle
    private async onCreateAssetBundles(encrypt=false) {
        let data = [];
        for (var key in this.bundles) {
            var cfg = this.bundles[key]
            if (cfg.select) {
                let ver = this.onCreateVersion();
                console.log(`自动生成 ${cfg.bundle} 版本号 ${ver}`);
                cfg.version = ver;
                data.push({
                    bundleName: cfg.bundle,
                    // isForce: false,
                    // channel: this.config.channelCfg,
                    version: cfg.version,
                    // minVersion: "0.0.0",
                    // remark: ""
                });
                let bPath = await this.onCreateBundle(cfg.bundle, encrypt);
                await Tools.zipDirc(bPath as string, path.join(this.buildOutPath, cfg.bundle), cfg.version)
                // let bPath = this.onCreateBundle(cfg.bundle)
                // if (this.config.serverCfg.name == "正式服" && bPath) {
                    // this.createCommitCfg(cfg)
                    // await Tools.zipDirc(bPath as string, cfg.bundle + "_" + cfg.version, cfg.version)
                // }
            }
        }
        this.createCommitCfg(data);
    }

    updateAndCommitSVN(directory: string): Promise<void> {
        return new Promise((resolve, reject) => {
            // SVN 更新命令
            const updateCommand = `svn update "${directory}"`;
    
            exec(updateCommand, (error, stdout, stderr) => {
                if (error) {
                    console.error(`[SVN 更新失败]: ${stderr}`);
                    reject(error);
                    return;
                }
                console.log(`[SVN 更新成功]: ${stdout}`);

                // 检查是否有冲突
                if (stdout.includes('C ')) {
                    console.error('存在冲突，请手动解决冲突后再提交。');
                    return;
                }
    
                // 提交新增和更新的文件
                this.commitChanges(directory)
                    .then(resolve)
                    .catch(reject);
            });
        });
    }
    
    commitChanges(directory: string): Promise<void> {
        return new Promise((resolve, reject) => {
            const commitMessage = `自动上传: ${new Date().toISOString()}`;
            // SVN 添加和提交命令
            const commitCommand = `svn add --force "${directory}" && svn commit -m "${commitMessage}" "${directory}"`;
    
            exec(commitCommand, (error, stdout, stderr) => {
                if (error) {
                    console.error(`[SVN 提交失败]: ${stderr}`);
                    reject(error);
                    return;
                }
                console.log(`[SVN 提交成功]: ${stdout}`);
                resolve();
            });
        });
    }

    //生成版本号
    onCreateVersion() {
        // var format = (num: number) => {
        //     return num < 10 ? `0` + num : num + ""
        // }
        // var chinaDate = new Date()
        // // 转换为印度时间
        // var indiaDate = new Date(chinaDate.getTime() - (2.5 * 60 * 60 * 1000));
        // var year = indiaDate.getFullYear();
        // var month = format(indiaDate.getMonth() + 1);
        // var day = format(indiaDate.getDate());
        // var hours = format(indiaDate.getHours());
        // var min = format(indiaDate.getMinutes());
        // var sec = format(indiaDate.getSeconds());
        // return `${this._config.versionName}.${year + month + day + hours + min + sec}`;
        return `${this._config.versionName}.${Tools.formatDateToStr()}`;
    }

    //创建manifest
    onCreateManifest(bundle: string, dir?: string) {
        if (!this.bundles[bundle]) {
            return null
        }
        let bundleCfg = this.bundles[bundle]

        let version = bundleCfg.version;
        let assetDir = dir ? dir : path.join(this.config.buildDir, "assets")

        let manifest: Manifest = {
            assets: {},
            bundle: bundle,
            packageUrl: this.config.serverCfg.cdn_address + `/${bundle}/${version}/`,
            version: version
        };
        // let relative = path.join(assetDir, bundleCfg.relative)
        // for (let i = 0; i < bundleCfg.respaths.length; i++) {
        //     var resPath = path.join(assetDir, bundleCfg.respaths[i])
        //     Tools.readDir(resPath, manifest.assets, assetDir);
        // }
        Tools.readDir(assetDir, manifest.assets, assetDir);
        return manifest
    }

    //生成assetbundle资源
    async onCreateBundle(bundle: string, bEncrypt?: boolean, outDir?: string) {
        if (!this.bundles[bundle]) {
            return null
        }

        //拷贝资源到输出目录
        let bundleCfg = this.bundles[bundle]
        let assetDir = path.join(this.config.buildDir, "data")
        outDir = outDir ? outDir : path.join(this.buildOutPath, bundle, bundleCfg.version)
        for (let i = 0; i < bundleCfg.respaths.length; i++) {
            var res = path.join(assetDir, bundleCfg.respaths[i])
            var dest = path.join(outDir, bundleCfg.respaths[i])
            Tools.copySourceDirToDesDir(res, bundleCfg.bundle == PACKAGE_MAIN ? dest : outDir)
            // Tools.copySourceDirToDesDir(res, dest);
        }
        //生成配置文件数据
        let manifest = this.onCreateManifest(bundle, outDir)
        if (!manifest)
            return;
        //保存manifest到输出目录
        let projectManifestPath = path.join(outDir, `project.manifest`);
        writeFileSync(projectManifestPath, JSON.stringify(manifest));
        if (bEncrypt) {
            let encryptPath = bundleCfg.bundle == PACKAGE_MAIN ? path.join(outDir, 'assets') : path.join(outDir);
            console.log("=======加密资源 开始=======");
            await encryptFolder(encryptPath);
            console.log("=======加密资源 结束=======");
        }

        //更新编辑器数据
        // this.bundles[bundle].versions.push(manifest.version)
        // this.bundles[bundle].versions.sort().reverse();
        this.bundles[bundle].version = manifest.version


        console.log("生成assetbundle资源成功 ", outDir)
        Editor.Message.send(PACKAGE_NAME, "onRefresh");
        return outDir;
    }

    public onShowInExport(bundle: string) {
        let outDir = path.join(this.buildOutPath, bundle)
        Tools.showInExplorer(outDir)
    }

    //打包
    async onBuildPackage() {
        if (!this.config.packageCfg) {
            console.log("未设置打包配置！！！！！")
            return;
        }
        if (this.config.autoCreate) {
            await this.onBuild()
        }
        this.buildAndroid();
    }

    private async buildAndroid() {
        if (!this.config.buildDir || !existsSync(this.config.buildDir)) {
            console.log("请设置工程目录！！！")
            return;
        }
        if (!this.config.packageCfg) {
            console.log("未设置打包配置！！！！！")
            return;
        }
        console.log("开始构建安卓工程------------>")
        const bEncrypt = helper.config.isEncrypt;
        if (bEncrypt) {
            await writeInCpp(this.config.enginePath);
        }
        console.log("拷贝资源到工程目录")
        let tmpAssetPath = path.join(this.config.buildDir, "tmpAssets")
        Tools.delDir(tmpAssetPath, true);
        Tools.mkdirSync(tmpAssetPath);
        for (var key in this.bundles) {
            var cfg = this.bundles[key]
            if (cfg.select || cfg.bundle == PACKAGE_MAIN) {
                let ver = this.onCreateVersion();
                console.log(`自动生成 ${cfg.bundle} 版本号 ${ver}`);
                cfg.version = ver;
                await this.onCreateBundle(cfg.bundle, bEncrypt, path.join(tmpAssetPath, cfg.relative))
            }
        }
        //保存bundle版本
        this.saveBundleCfg()
        let assetPath = path.join(this.config.buildDir, "data")
        copyFileSync(path.join(assetPath, "application.js"), path.join(tmpAssetPath, "application.js"))
        copyFileSync(path.join(assetPath, "main.js"), path.join(tmpAssetPath, "main.js"))
        Tools.delDir(assetPath, true);
        renameSync(tmpAssetPath, assetPath );
        console.log("资源拷贝结束")
        // if (bEncrypt) {
        //     // await this.encryptBuildAssetBundles(assetPath);
        //     let outDir = path.join(assetPath, 'assets');
        //     console.log("=======加密资源 开始=======");
        //     await encryptFolder(outDir);
        //     console.log("=======加密资源 结束=======");
        // }
        AndroidBuilder.build(this.config.packageCfg)
    }

    private _createProgress = 0;
    private resetCreateProgress() {
        this._createProgress = 0;
        Editor.Message.send(PACKAGE_NAME, "updateCreateProgress", 0);
    }
    private addCreateProgress() {
        this._createProgress++;
        let value = (this._createProgress / this.total) * 100;
        Editor.Message.send(PACKAGE_NAME, "updateCreateProgress", value);
    }

    private remake() {
        if (os.type() !== 'Darwin') {//判断mac os平台
            return
        }
    //     const projectPath = Editor.Project.path
    //     const nativeIosPath = projectPath + "/native/engine/ios"
    //     const iosProjPath = projectPath + "/build/ios/proj"
    //     const resPath = projectPath + "/build/ios"
    //     if (!existsSync(resPath) || !existsSync(nativeIosPath)) {
    //         return;
    //     }
    //     const prev = path.resolve(Editor.App.path, "..")
    //     const cmake = prev + "/tools/cmake/bin/cmake"//cocos目录下的cmake执行程序
    //     console.log(cmake)
    //     const cmd = cmake + " with -S " + nativeIosPath + " -GXcode -B" + iosProjPath +
    //         " -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang -DRES_DIR=" + resPath
    //     exec(cmd, { encoding: 'utf8' });
    // }
    // /**@description 删除不包含在包内的bundles */
    // async onDelBundles() {
    //     const config = {
    //         title: '警告',
    //         detail: '',
    //         buttons: ['取消', '确定'],
    //     };
    //     const code = await Editor.Dialog.info('执行此操作将会删除不包含在包内的所有bundles,是否继续？', config);
    //     if (code.response == 1) {
    //         this.removeNotInApkBundle();
    //         this.remake()
    //     }
    }

    /**@description 删除不包含在包内的所有bundles */
    private removeNotInApkBundle() {
        // Editor.Message.send(PACKAGE_NAME, "onSetProcess", true);
        // let keys = Object.keys(this.bundles);
        // let removeBundles: string[] = [];
        // keys.forEach((key) => {
        //     if (!this.bundles[key].select) {
        //         removeBundles.push(key);
        //     }
        // });
        // let manifests = [];
        // let removeDirs = [];
        // for (let i = 0; i < removeBundles.length; i++) {
        //     let key = removeBundles[i];
        //     removeDirs.push(path.join(this.config.buildDir, `assets/${key}`));
        //     manifests.push(path.join(this.config.buildDir, `manifest/${key}_project.json`));
        //     manifests.push(path.join(this.config.buildDir, `manifest/${key}_version.json`));
        // }

        // for (let i = 0; i < removeDirs.length; i++) {
        //     this.log(`删除目录 : ${removeDirs[i]}`);
        //     Tools.delDir(removeDirs[i], true);
        // }

        // for (let i = 0; i < manifests.length; i++) {
        //     this.log(`删除版本文件 : ${manifests[i]}`);
        //     Tools.delFile(manifests[i]);
        // }
        // Editor.Message.send(PACKAGE_NAME, "onSetProcess", false);
    }

    // private client = new OSS({
    //     region: 'oss-cn-hongkong',
    //     accessKeyId: 'LTAI5tPR71aq1HicV85FfbWF',
    //     accessKeySecret: 'fLEMvGPXOjdg7AcmsXCjK9jkB9HQTc',
    //     bucket: 'game-aaa'
    // });
    // 配置 AWS 访问凭证和区域
    // private s3Client = new S3Client({
    //     region: 'ap-south-1', // 例如：'us-west-2'
    //     credentials: {
    //         accessKeyId: 'AKIA4J4LVNA7MJVEE3G7',
    //         secretAccessKey: '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'
    //     }
    // });
    public uploadCount: number = 0
    async upload(_source: string, _dest: string) {
        let files = readdirSync(_source);
        for (let i = 0; i < files.length; i++) {
            let filename = files[i]
            let sourcePath = _source + "/" + filename;
            let destPath = _dest + "/" + filename;
            var stats = statSync(sourcePath)
            if (stats.isFile()) {
                console.log('######## sourcePath ready ---> ', sourcePath);
                // 读取文件
                // const fileContent = fs.readFileSync(sourcePath);
                // // 配置 S3 上传参数
                // const params: PutObjectCommandInput = {
                //     Bucket: bucketName,
                //     Key: destPath,
                //     Body: fileContent,
                //     ACL: "public-read", // 设置文件权限，这里设置为公共读
                // };

                // // 设置重试次数和延迟
                // const maxRetries = 30;
                // let retryCount = 0;
                // const retryDelay = 1000; // 3 秒

                // // 重试上传文件操作
                // while (retryCount < maxRetries) {
                //     try {
                //     // 执行上传操作
                //     const data = await this.s3Client.send(new PutObjectCommand(params), { requestTimeout: 3000 });
                //         // console.log("File uploaded successfully. ETag:", data.ETag);
                //         console.log(`${sourcePath} uploaded successfully.`);
                //         this.uploadCount++;
                //         break; // 如果上传成功，退出循环
                //     } catch (err) {
                //         console.error(`${sourcePath} uploaded Error.`);
                //         console.error("Error uploading file:", err);
                //         if ((err as { name: string }).name === 'TimeoutError' || (err as { code: string }).code === 'ECONNRESET') {
                //             retryCount++;
                //         console.log(`Retrying upload (attempt ${retryCount} of ${maxRetries})...`);
                //         await new Promise(resolve => setTimeout(resolve, retryDelay));
                //     } else {
                //         // 非连接重置或超时错误，不重试
                //         break;
                //     }
                //     }
                // }


                // try {
                //     // 执行上传操作
                //     const data = await this.s3Client.send(new PutObjectCommand(uploadParams));
                //     console.log("File uploaded successfully. ETag:", data.ETag);
                //   } catch (err) {
                //     console.error("Error uploading file:", err);
                //     // 在这里处理连接重置或超时错误
                //   }
            }
            else {
                stats.isDirectory() && await this.upload(sourcePath, destPath)
            }
        }
    }

    async onDeployToSVN() {
        await this.updateAndCommitSVN(this.buildOutPath);
    }

    async onDeployToOSS(bundle: string) {
        try {
            let resPath = path.join(this.buildOutPath, bundle, this._bundles![bundle].version)
            if (!existsSync(resPath)) {
                console.error("资源部署失败,文件路径不存在 " + resPath)
                return;
            }
            let prePath = "test";
            if (this.config.serverCfg.name == "正式服") {
                prePath =  "publish";
            }
            let outPath = `${prePath}/${bundle}/${this._bundles![bundle].version}`
            console.log("本地上传的资源路径 " + resPath)
            console.log("服务器存储资源路径 " + outPath)
            this.uploadCount = 0
            await this.upload(resPath, outPath)
            console.log(`=======================Bundle: ${bundle} Version:${this._bundles![bundle].version} 上传成功 数量${this.uploadCount}===============================`)
            this.uploadCount = 0
        } catch (e) {
            console.error('error: %j', e);
        }
    }
    /**
     * @description 部署
     */
    onDeployToRemote() {
        // if (this.config.serverCfg.cdn_address.length <= 0) {
        //     this.log("[部署]请先选择本地服务器目录");
        //     return;
        // }
        // if (!existsSync(this.config.serverCfg.cdn_address)) {
        //     this.log(`[部署]本地测试服务器目录不存在 : ${this.config.serverCfg.cdn_address}`);
        //     return;
        // }
        // if (!existsSync(this.config.buildDir)) {
        //     this.log(`[部署]构建目录不存在 : ${this.config.buildDir} , 请先构建`);
        //     return;
        // }
        // Editor.Message.send(PACKAGE_NAME, "onSetProcess", true);
        // let includes: string[] = [] //this.mainBundleIncludes;

        // let temps = [];
        // for (let i = 0; i < includes.length; i++) {
        //     //只保留根目录
        //     let dir = includes[i];
        //     let index = dir.search(/\\|\//);
        //     if (index == -1) {
        //         if (temps.indexOf(dir) == -1) {
        //             temps.push(dir);
        //         }
        //     } else {
        //         dir = dir.substr(0, index);
        //         if (temps.indexOf(dir) == -1) {
        //             temps.push(dir);
        //         }
        //     }
        // }

        // let copyDirs = ["manifest"].concat(temps);
        // for (let i = 0; i < copyDirs.length; i++) {
        //     let dir = path.join(this.config.buildDir, copyDirs[i]);
        //     if (!existsSync(dir)) {
        //         this.log(`${this.config.buildDir} [部署]不存在${copyDirs[i]}目录,无法拷贝文件`);
        //         return;
        //     }
        // }

        // this.log(`[部署]开始拷贝文件到 : ${this.config.serverCfg.cdn_address}`);
        // this.resetProgress();
        // this.log(`[部署]删除旧目录 : ${this.config.serverCfg.cdn_address}`);
        // let count = Tools.getDirFileCount(this.config.serverCfg.cdn_address);
        // this.log(`[部署]删除文件个数:${count}`);
        // Tools.delDir(this.config.serverCfg.cdn_address);

        // count = 0;
        // for (let i = 0; i < copyDirs.length; i++) {
        //     let dir = path.join(this.config.buildDir, copyDirs[i]);
        //     count += Tools.getDirFileCount(dir);
        // }

        // //压缩文件数量
        // let zipPath = Editor.Project.path + "/PackageVersion";
        // count += Tools.getDirFileCount(zipPath);

        // this.log(`[部署]复制文件个数 : ${count}`);

        // for (let i = 0; i < copyDirs.length; i++) {
        //     let source = path.join(this.config.buildDir, copyDirs[i]);
        //     let dest = path.join(this.config.serverCfg.cdn_address, copyDirs[i]);
        //     this.log(`[部署]复制${source} => ${dest}`);
        //     Tools.copySourceDirToDesDir(source, dest, () => {
        //         this.addProgress();
        //     });
        // }

        // let remoteZipPath = path.join(this.config.serverCfg.cdn_address, "zips");
        // Tools.delDir(remoteZipPath);

        // //部署压缩文件
        // this.log(`[部署]复制${zipPath} => ${remoteZipPath}`);
        // Tools.copySourceDirToDesDir(zipPath, remoteZipPath, () => {
        //     this.addProgress();
        // });

    }

    /**
     * @description 构建
     */
    onBuild() {
        this.onChangeGameConfig();
        return new Promise((resolve, reject) => {
            let buildConfig = `configPath=${this.buildConfigPath}`
            console.log("buildConfig  " + buildConfig)
            let enginePath = this.config.enginePath;
            if (isIOS) {
                enginePath += "/Contents/MacOS/CocosCreator";
            }
            let cmd = `${enginePath} --project "${Editor.Project.path}" --build ${buildConfig}`
            console.log("CMD: " + cmd)
            console.log("===================================构建发布 Start================================")
            exec(cmd, { encoding: `utf8` }, (error, stdout, stderr) => {
                if (error) {
                    console.error(`exec error: ${error}`);
                    //return;
                }
                console.log(`stdout: ${stdout}`);
                console.error(`stderr: ${stderr}`)
                console.log("===================================构建发布 End================================")
                resolve(0)
            })
        })

    }

    async encryptBuildAssetBundles() {
        console.log("=======加密资源 开始=======");
        // this.bundles
        for (const key in this.bundles) {
            if (Object.prototype.hasOwnProperty.call(this.bundles, key)) {
                const cfg = this.bundles[key];
                console.log(JSON.stringify(cfg));
                if (cfg.select) {
                    let outDir = path.join(this.buildOutPath, key, this.config.platform, cfg.version, 'assets')
                    // console.log('待加密目录',outDir);
                    await encryptFolder(outDir);
                }
                
            }
        }
        console.log("=======加密资源 结束=======");
    }


    /**@description 进度总数 */
    private total = 1;
    private addProgress() {
        this._progress++;
        let value = (this._progress / this.total) * 100;
        if (value >= 100) {
            Editor.Message.send(PACKAGE_NAME, "onSetProcess", false);
        }
        Editor.Message.send(PACKAGE_NAME, "updateDeployProgress", value);
    }
    private _progress = 0;
    private resetProgress() {
        this._progress = 0;
        Editor.Message.send(PACKAGE_NAME, "updateDeployProgress", 0);
    }


    onBeforeBuild() {
        console.log("onBeforeBuild---------------------->")
        this.resetProgress();
        this.resetCreateProgress();
        Editor.Message.send(PACKAGE_NAME, "onSetProcess", true);
    }

    onAfterBuild(dest: string) {
        console.log("onAfterBuild---------------------->", dest)
        //this.onCreateAllManifest(dest)
        this.onInsertHotupdate(dest);
        this.readCacheConfig();
        //this.config.buildDir = normalize(join(dest, "assets"));
        Editor.Message.send(PACKAGE_NAME, "onSetBuildDir", this.config.buildDir);
        this.saveConfig();
    }

    onPngCompressComplete() {
        this.readCacheConfig();
    }

    http_get(url: string, callback?: any) {
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function () {
            if (xhr.readyState == 4) {
                if (xhr.status == 200) {
                    if (callback) {
                        callback(xhr.responseText)
                    }
                } else {
                    console.warn("http request error:", xhr.responseText)
                }
            }
        };
        xhr.timeout = 5000
        xhr.ontimeout = function (e) {
            xhr.abort()
            console.error("http request timeout:", e)
        }
        xhr.open("GET", url, true);
        xhr.send();
    }
    
    http_post(requestId: string, paramStr: string, callback?: Function) {
        // console.log("------------------------------------------")
        // console.log("requestId = ", requestId)
        // console.log("paramStr = ", paramStr)
        // console.log("------------------------------------------")
        // var xhr = new XMLHttpRequest();
        // //设置超时链接
        // xhr.open('post', this.config.serverCfg.res_address + requestId );
        // xhr.timeout = 15000;
        // xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        // xhr.onreadystatechange = ()=> {
        //     // 返回一个无符号短整型（unsigned short）数字，代表请求的响应状态。
        //     let code = xhr.status;
        //     //返回一个 DOMString，该 DOMString 包含对请求的响应，如果请求未成功或尚未发送，则返回 null。
        //     let response = xhr.responseText;
        //     //返回 一个无符号短整型（unsigned short）数字，代表请求的状态码。
        //     let readyState = xhr.readyState;
        //     if (readyState == 4) {
        //         if (code == 200) {
        //             try {
        //                 console.log(`${requestId} response ================= code : ${code} `, response);
        //                 let resJson = JSON.parse(response);
        //                 callback && callback(code, resJson);
        //             } catch (error) {
        //                 console.log('err ==', error);
        //                 callback && callback(error);
        //             }

        //         } else {
        //             console.log(`${requestId} response ================= code : ${code} `, response);
        //         }
        //     }
        // };
        // xhr.ontimeout = function (e) {
        //     xhr.abort()
        //     console.error("http request timeout:", e)
        // }
        // xhr.onerror = (event) => {
        //     console.error(`${requestId} response onerror=================`, event);
        // }
        // xhr.send(paramStr);
    }

    private paramToSortStr(param: { [key: string]: any }) {
        let keys = Object.keys(param).sort();
        let paramStr = "";
        for (let k of keys) {
            if (param[k] !== '') {
                paramStr += k + "=" + param[k] + "&";
            }
        }
        return paramStr;
    }

    private createSign(param: { [key: string]: any }) {
        let paramStr = this.paramToSortStr(param);
        let keyParam = paramStr + 'key=751a276cae97ac29e91819106ebb62f0';
        //签名
        return paramStr + 'sign=' + require("crypto").createHash('md5').update(keyParam).digest('hex');
    }

}

export const helper = new Helper();